#include "ssd1306Oled.h"

#define SSD1306_WIDTH           128
#define SSD1306_HEIGHT          64
#define SSD1306_PAGE_COUNT      (SSD1306_HEIGHT / 8)

static uint8_t ssd1306_buffer[SSD1306_PAGE_COUNT][SSD1306_WIDTH];

static esp_err_t ssd1306_send_cmd(uint8_t cmd);
static esp_err_t ssd1306_send_data(uint8_t *data, size_t len);
static void ssd1306_clear(void);
void ssd1306_draw_string(uint8_t x, uint8_t page, const char *str) ;

void ssd1306_init(void) 
{
    iic_init();

    ssd1306_send_cmd(0xAE); // 显示关闭

    ssd1306_send_cmd(0x20); // 设置内存模式
    ssd1306_send_cmd(0x00); // 水平寻址模式

    ssd1306_send_cmd(0xB0); // 页地址

    ssd1306_send_cmd(0xC8); // 扫描方向

    ssd1306_send_cmd(0x00); // 低列起始地址

    ssd1306_send_cmd(0x10); // 高列起始地址

    ssd1306_send_cmd(0x40); // 起始行

    ssd1306_send_cmd(0x81); // 对比度
    ssd1306_send_cmd(0x7F);

    ssd1306_send_cmd(0xA1); // 段重映射

    ssd1306_send_cmd(0xA6); // 正常显示

    ssd1306_send_cmd(0xA8); // 多路复用比
    ssd1306_send_cmd(0x3F);

    ssd1306_send_cmd(0xA4); // 从 RAM 恢复显示

    ssd1306_send_cmd(0xD3); // 显示偏移
    ssd1306_send_cmd(0x00);

    ssd1306_send_cmd(0xD5); // 显示时钟分频
    ssd1306_send_cmd(0x80);

    ssd1306_send_cmd(0xD9); // 预充电周期
    ssd1306_send_cmd(0xF1);

    ssd1306_send_cmd(0xDA); // COM 引脚硬件配置
    ssd1306_send_cmd(0x12);

    ssd1306_send_cmd(0xDB); // VCOMH
    ssd1306_send_cmd(0x40);

    ssd1306_send_cmd(0x8D); // 电荷泵
    ssd1306_send_cmd(0x14);

    ssd1306_send_cmd(0xAF); // 打开显示

    ssd1306_clear();

    // test
    ssd1306_draw_string(0, 0, "Hello ESP32-S3!");
    ssd1306_draw_string(0, 1, "Hello LVGL!");
}

static esp_err_t ssd1306_send_cmd(uint8_t cmd)
{
    uint8_t buffer[2];

    buffer[0] = 0x00;
    buffer[1] = cmd;

    return i2c_master_wite_bytes(buffer, 2);
}

static esp_err_t ssd1306_send_data(uint8_t *data, size_t len)
{
    uint8_t buffer[len + 1];

    buffer[0] = 0x40;
    memcpy(&buffer[1], data, len);

    return i2c_master_wite_bytes(buffer, len + 1);
}

static void ssd1306_clear(void)
{
    uint8_t zero[SSD1306_WIDTH];

    memset(zero, 0x00, sizeof(zero));

    for (uint8_t page = 0; page < 8; page++) 
    {
        ssd1306_send_cmd(0xB0 + page);
        ssd1306_send_cmd(0x00);
        ssd1306_send_cmd(0x10);
        ssd1306_send_data(zero, sizeof(zero));
    }
}

void ssd1306_draw_char(uint8_t x, uint8_t page, char ch) 
{
    uint8_t buf[6];

    if (ch < 0x20 || ch > 0x7F)
    {
        ch = '?';
    }

    ssd1306_send_cmd(0xB0 + page);
    ssd1306_send_cmd(0x00 + (x & 0x0F));
    ssd1306_send_cmd(0x10 + ((x >> 4) & 0x0F));
    
    memcpy(buf, font5x8[ch - 0x20], 5);
    buf[5] = 0x00; // 空列间隔
    ssd1306_send_data(buf, 6);
}

void ssd1306_draw_string(uint8_t x, uint8_t page, const char *str) 
{
    while (*str) 
    {
        ssd1306_draw_char(x, page, *str++);
        x += 6; // 每个字符占 6 列
        if (x + 6 > SSD1306_WIDTH)
        {
            break;
        }
    }
}



